#include <sched.h>
#include <irq.h>
#include <task.h>

run_queue g_rq;

/*preempt_schdule*/

void tick_handle_periodic(){
    run_queue *rq = &g_rq;

    task_tick(rq, current);
}

static void schedule_debug(task_struct *p){
    if(preempt_counter() != 1)
		printk("BUG: scheduling while atomic: %d, 0x%x\n",
				p->pid, preempt_counter());
}

task_struct *pick_next_task(run_queue *rq, task_struct *p)
{
    const struct sched_class *class = &simple_sched_class;

    return class->pick_next_task(rq, p);
}

void schedule_tail(task_struct *prev){
    raw_local_irq_enable();
}

void dequeue_task(run_queue *rq, task_struct *p)
{
    const struct sched_class *class = &simple_sched_class;

    return class->dequeue_task(rq, p);
}

void enqueue_task(run_queue *rq, task_struct *p)
{
    const struct sched_class *class = &simple_sched_class;

    return class->enqueue_task(rq, p);
}

void task_tick(run_queue *rq, task_struct *p)
{
    const struct sched_class *class = &simple_sched_class;

    return class->task_tick(rq, p);
}

static void __schedule(){
    task_struct *prev, *next, *last;
    run_queue *rq = &g_rq;
    printk("DEBUG 1 %s \n",__func__);
    prev = current;

    schedule_debug(prev);

    raw_local_irq_disable();
    printk("DEBUG 2 %s \n",__func__);

    if(prev->state)
        dequeue_task(rq, prev);
    printk("DEBUG 3 %s \n",__func__);

    next = pick_next_task(rq, prev);
    clear_task_resched(prev);
    printk("DEBUG 4 %s \n",__func__);

    if(next != prev) {
        last = switch_to(prev, next);

        rq->nr_switches++;
        rq->curr = current;
    }
    printk("DEBUG 5 %s \n",__func__);

    schedule_tail(last);
    printk("DEBUG 6 %s \n",__func__);

}

void wake_up_process(struct task_struct *p)
{
	struct run_queue *rq = &g_rq;

	p->state = TASK_RUNNING;

	enqueue_task(rq, p);
}

void preempt_schedule_irq(void){
    if(preempt_counter())
		printk("BUG: %s incorrect preempt count: 0x%x\n",
				__func__, preempt_counter());
    preempt_disable();

    raw_local_irq_enable();
    __schedule();
    raw_local_irq_disable();
    preempt_enable();
}

void sched_init(void){

    run_queue *rq = &g_rq;
    INIT_LIST_HEAD(&g_rq.rq_head);
    g_rq.nr_running = 0;
    g_rq.nr_switches = 0;
    g_rq.curr = NULL;
}
